---
title: DOM Manipulation and Event Handling
description: Learn to create dynamic, interactive user interfaces by mastering DOM manipulation and event handling, transitioning from backend logic to frontend user interaction.
---

# DOM Manipulation and Event Handling

As a Python developer, you're used to working with data structures and algorithms. In frontend development, the Document Object Model (DOM) becomes your primary data structure for creating interactive user interfaces. This module teaches you how to manipulate the DOM and handle user events effectively.

## Understanding the DOM

### From Python Data Structures to DOM

<PythonEditor title="Data Structure Manipulation Comparison" compare={true}>
```python !! py
# Python: Working with data structures (lists, dicts)
import json
from datetime import datetime

class TaskManager:
    """
    Python approach: Working with native data structures
    - Direct manipulation of lists and dictionaries
    - No visual representation by default
    - Focus on data logic and algorithms
    """
    
    def __init__(self):
        self.tasks = []
        self.categories = {}
    
    def add_task(self, title, description, category="general"):
        """Add a new task to the data structure"""
        task = {
            "id": len(self.tasks) + 1,
            "title": title,
            "description": description,
            "category": category,
            "completed": False,
            "created_at": datetime.now().isoformat()
        }
        
        # Add to main list
        self.tasks.append(task)
        
        # Update categories
        if category not in self.categories:
            self.categories[category] = []
        self.categories[category].append(task["id"])
        
        print(f"Task added: {task['title']}")
        return task
    
    def complete_task(self, task_id):
        """Mark a task as completed"""
        for task in self.tasks:
            if task["id"] == task_id:
                task["completed"] = True
                task["completed_at"] = datetime.now().isoformat()
                print(f"Task completed: {task['title']}")
                return True
        return False
    
    def filter_tasks(self, completed=None, category=None):
        """Filter tasks based on criteria"""
        filtered = self.tasks
        
        if completed is not None:
            filtered = [t for t in filtered if t["completed"] == completed]
        
        if category:
            filtered = [t for t in filtered if t["category"] == category]
        
        return filtered
    
    def display_tasks(self):
        """Display tasks in console"""
        print("\n=== Task List ===")
        for task in self.tasks:
            status = "✓" if task["completed"] else "○"
            print(f"{status} [{task['category']}] {task['title']}")
            print(f"   {task['description']}")
        print("================")

# Python usage: Working with data in memory
task_manager = TaskManager()

# Add some tasks
task_manager.add_task("Learn JavaScript", "Master frontend development", "education")
task_manager.add_task("Build a website", "Create personal portfolio", "project")
task_manager.add_task("Study algorithms", "Prepare for interviews", "education")

# Manipulate data
task_manager.complete_task(1)

# Filter and display
education_tasks = task_manager.filter_tasks(category="education")
print(f"Education tasks: {len(education_tasks)}")

task_manager.display_tasks()
```

```javascript !! js
// JavaScript: Working with DOM (Document Object Model)
// The DOM is a live data structure that represents the HTML document

class TaskDOMManager {
    /**
     * JavaScript approach: Working with DOM elements
     * - Visual representation is built-in
     * - Elements have both data and visual properties
     * - Changes immediately reflect in the user interface
     */
    
    constructor() {
        this.tasks = [];
        this.taskContainer = document.getElementById('tasks-container');
        this.taskForm = document.getElementById('task-form');
        this.setupEventListeners();
        this.initializeDOM();
    }
    
    initializeDOM() {
        // Create initial DOM structure if it doesn't exist
        if (!this.taskContainer) {
            this.createTaskContainer();
        }
        if (!this.taskForm) {
            this.createTaskForm();
        }
    }
    
    createTaskContainer() {
        // Create DOM elements programmatically
        this.taskContainer = document.createElement('div');
        this.taskContainer.id = 'tasks-container';
        this.taskContainer.className = 'tasks-list';
        
        // Add to document
        document.body.appendChild(this.taskContainer);
    }
    
    createTaskForm() {
        // Create a form for adding tasks
        this.taskForm = document.createElement('form');
        this.taskForm.id = 'task-form';
        this.taskForm.innerHTML = `
            <div class="form-group">
                <input type="text" id="task-title" placeholder="Task title" required>
                <input type="text" id="task-description" placeholder="Description">
                <select id="task-category">
                    <option value="general">General</option>
                    <option value="education">Education</option>
                    <option value="project">Project</option>
                </select>
                <button type="submit">Add Task</button>
            </div>
        `;
        
        // Insert at the beginning of body
        document.body.insertBefore(this.taskForm, this.taskContainer);
    }
    
    addTask(title, description, category = "general") {
        /**
         * Add task: Both data and DOM manipulation
         * - Store in data structure (like Python)
         * - Create visual representation (unique to frontend)
         */
        const task = {
            id: Date.now(), // Simple ID generation
            title: title,
            description: description,
            category: category,
            completed: false,
            createdAt: new Date().toISOString()
        };
        
        // Add to data structure
        this.tasks.push(task);
        
        // Create DOM element for the task
        const taskElement = this.createTaskElement(task);
        
        // Add to DOM with animation
        this.taskContainer.appendChild(taskElement);
        
        // Animate the new task appearance
        taskElement.style.opacity = '0';
        taskElement.style.transform = 'translateY(-20px)';
        
        // Trigger animation
        requestAnimationFrame(() => {
            taskElement.style.transition = 'all 0.3s ease';
            taskElement.style.opacity = '1';
            taskElement.style.transform = 'translateY(0)';
        });
        
        console.log(`Task added to DOM: ${task.title}`);
        return task;
    }
    
    createTaskElement(task) {
        // Create DOM representation of a task
        const taskDiv = document.createElement('div');
        taskDiv.className = `task-item ${task.completed ? 'completed' : ''}`;
        taskDiv.dataset.taskId = task.id; // Store ID in DOM
        
        taskDiv.innerHTML = `
            <div class="task-header">
                <span class="task-category">${task.category}</span>
                <button class="complete-btn" data-action="complete">
                    ${task.completed ? '✓' : '○'}
                </button>
            </div>
            <h3 class="task-title">${task.title}</h3>
            <p class="task-description">${task.description}</p>
            <div class="task-actions">
                <button class="edit-btn" data-action="edit">Edit</button>
                <button class="delete-btn" data-action="delete">Delete</button>
            </div>
        `;
        
        return taskDiv;
    }
    
    completeTask(taskId) {
        // Update both data and DOM
        const task = this.tasks.find(t => t.id == taskId);
        if (!task) return false;
        
        // Update data
        task.completed = !task.completed;
        task.completedAt = task.completed ? new Date().toISOString() : null;
        
        // Update DOM element
        const taskElement = document.querySelector(`[data-task-id="${taskId}"]`);
        if (taskElement) {
            // Update visual state
            taskElement.classList.toggle('completed', task.completed);
            
            // Update button text
            const completeBtn = taskElement.querySelector('.complete-btn');
            completeBtn.textContent = task.completed ? '✓' : '○';
            
            // Add completion animation
            if (task.completed) {
                taskElement.style.transform = 'scale(1.05)';
                setTimeout(() => {
                    taskElement.style.transform = 'scale(1)';
                }, 200);
            }
        }
        
        console.log(`Task ${task.completed ? 'completed' : 'uncompleted'}: ${task.title}`);
        return true;
    }
    
    deleteTask(taskId) {
        // Remove from both data and DOM
        const taskIndex = this.tasks.findIndex(t => t.id == taskId);
        if (taskIndex === -1) return false;
        
        // Remove from data
        const task = this.tasks.splice(taskIndex, 1)[0];
        
        // Remove from DOM with animation
        const taskElement = document.querySelector(`[data-task-id="${taskId}"]`);
        if (taskElement) {
            // Animate removal
            taskElement.style.transition = 'all 0.3s ease';
            taskElement.style.opacity = '0';
            taskElement.style.transform = 'translateX(-100%)';
            
            // Remove after animation
            setTimeout(() => {
                taskElement.remove();
            }, 300);
        }
        
        console.log(`Task deleted: ${task.title}`);
        return true;
    }
    
    filterTasks(completed = null, category = null) {
        // Filter tasks and update DOM display
        const allTaskElements = document.querySelectorAll('.task-item');
        
        allTaskElements.forEach(element => {
            const taskId = element.dataset.taskId;
            const task = this.tasks.find(t => t.id == taskId);
            
            let shouldShow = true;
            
            // Apply filters
            if (completed !== null && task.completed !== completed) {
                shouldShow = false;
            }
            
            if (category && task.category !== category) {
                shouldShow = false;
            }
            
            // Show/hide with animation
            if (shouldShow) {
                element.style.display = 'block';
                element.style.opacity = '1';
            } else {
                element.style.opacity = '0.3';
                element.style.display = 'none';
            }
        });
    }
    
    setupEventListeners() {
        // Set up form submission
        document.addEventListener('submit', (event) => {
            if (event.target.id === 'task-form') {
                event.preventDefault();
                this.handleFormSubmit(event);
            }
        });
        
        // Set up task interactions using event delegation
        document.addEventListener('click', (event) => {
            const action = event.target.dataset.action;
            const taskElement = event.target.closest('.task-item');
            
            if (!taskElement) return;
            
            const taskId = taskElement.dataset.taskId;
            
            switch (action) {
                case 'complete':
                    this.completeTask(taskId);
                    break;
                case 'edit':
                    this.editTask(taskId);
                    break;
                case 'delete':
                    this.deleteTask(taskId);
                    break;
            }
        });
    }
    
    handleFormSubmit(event) {
        const formData = new FormData(event.target);
        const title = document.getElementById('task-title').value;
        const description = document.getElementById('task-description').value;
        const category = document.getElementById('task-category').value;
        
        if (title.trim()) {
            this.addTask(title, description, category);
            event.target.reset(); // Clear form
        }
    }
    
    editTask(taskId) {
        // Inline editing functionality
        const taskElement = document.querySelector(`[data-task-id="${taskId}"]`);
        const task = this.tasks.find(t => t.id == taskId);
        
        if (!taskElement || !task) return;
        
        const titleElement = taskElement.querySelector('.task-title');
        const descriptionElement = taskElement.querySelector('.task-description');
        
        // Make elements editable
        titleElement.contentEditable = true;
        descriptionElement.contentEditable = true;
        titleElement.focus();
        
        // Add editing styles
        titleElement.classList.add('editing');
        descriptionElement.classList.add('editing');
        
        // Handle save on Enter or blur
        const saveEdit = () => {
            task.title = titleElement.textContent.trim();
            task.description = descriptionElement.textContent.trim();
            
            titleElement.contentEditable = false;
            descriptionElement.contentEditable = false;
            titleElement.classList.remove('editing');
            descriptionElement.classList.remove('editing');
            
            console.log(`Task edited: ${task.title}`);
        };
        
        titleElement.addEventListener('blur', saveEdit, { once: true });
        titleElement.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') {
                e.preventDefault();
                saveEdit();
            }
        }, { once: true });
    }
}

// Initialize DOM-based task manager
const domTaskManager = new TaskDOMManager();

// Add some sample tasks
domTaskManager.addTask("Learn DOM Manipulation", "Master JavaScript DOM APIs", "education");
domTaskManager.addTask("Build Interactive UI", "Create dynamic user interfaces", "project");
domTaskManager.addTask("Handle User Events", "Implement event listeners", "education");

// JavaScript DOM characteristics:
// 1. Visual and data representation combined
// 2. Real-time updates to user interface
// 3. Event-driven user interactions
// 4. Animation and visual feedback
console.log("JavaScript: DOM manipulation with visual feedback and real-time updates");
```
</PythonEditor>

## Event-Driven User Interactions

### From Function Calls to Event Handlers

<PythonEditor title="User Interaction Patterns" compare={true}>
```python !! py
# Python: Function-based interaction (CLI/programmatic)
import cmd
import sys
from datetime import datetime

class TaskCLI(cmd.Cmd):
    """
    Python approach: Command-line interface
    - Sequential command processing
    - Text-based user interaction
    - No concurrent user actions
    """
    
    intro = 'Welcome to Task Manager CLI. Type help or ? to list commands.\n'
    prompt = '(task) '
    
    def __init__(self):
        super().__init__()
        self.tasks = []
        self.current_id = 1
    
    def do_add(self, line):
        """Add a new task: add <title> | <description>"""
        try:
            parts = line.split(' | ')
            title = parts[0].strip()
            description = parts[1].strip() if len(parts) > 1 else ""
            
            task = {
                'id': self.current_id,
                'title': title,
                'description': description,
                'completed': False,
                'created': datetime.now()
            }
            
            self.tasks.append(task)
            self.current_id += 1
            print(f"Task added: {title}")
            
        except Exception as e:
            print(f"Error: {e}")
    
    def do_list(self, line):
        """List all tasks"""
        if not self.tasks:
            print("No tasks found.")
            return
        
        print("\n=== Task List ===")
        for task in self.tasks:
            status = "✓" if task['completed'] else "○"
            print(f"{task['id']}. {status} {task['title']}")
            if task['description']:
                print(f"   {task['description']}")
        print("================\n")
    
    def do_complete(self, line):
        """Mark task as completed: complete <id>"""
        try:
            task_id = int(line.strip())
            task = next((t for t in self.tasks if t['id'] == task_id), None)
            
            if task:
                task['completed'] = True
                print(f"Task completed: {task['title']}")
            else:
                print(f"Task {task_id} not found.")
                
        except ValueError:
            print("Please provide a valid task ID.")
    
    def do_delete(self, line):
        """Delete a task: delete <id>"""
        try:
            task_id = int(line.strip())
            task = next((t for t in self.tasks if t['id'] == task_id), None)
            
            if task:
                self.tasks.remove(task)
                print(f"Task deleted: {task['title']}")
            else:
                print(f"Task {task_id} not found.")
                
        except ValueError:
            print("Please provide a valid task ID.")
    
    def do_quit(self, line):
        """Exit the program"""
        print("Goodbye!")
        return True
    
    def do_EOF(self, line):
        """Handle Ctrl+D"""
        return self.do_quit(line)

# Python CLI usage
if __name__ == "__main__":
    print("Python CLI Task Manager:")
    print("- Sequential command processing")
    print("- Text-based interaction")
    print("- Single-threaded execution")
    
    # This would start the CLI loop
    # TaskCLI().cmdloop()
    
    # Simulated interaction
    cli = TaskCLI()
    print("\nSimulating CLI commands:")
    cli.do_add("Learn Python | Master backend development")
    cli.do_add("Build API | Create REST API")
    cli.do_list("")
    cli.do_complete("1")
    cli.do_list("")
```

```javascript !! js
// JavaScript: Event-driven user interface
// Multiple concurrent user interactions

class InteractiveTaskManager {
    /**
     * JavaScript approach: Event-driven interface
     * - Multiple simultaneous user interactions
     * - Visual feedback for all actions
     * - Asynchronous event handling
     */
    
    constructor() {
        this.tasks = [];
        this.currentId = 1;
        this.isEditing = false;
        this.setupInterface();
        this.setupEventListeners();
        this.setupKeyboardShortcuts();
    }
    
    setupInterface() {
        // Create a rich, interactive interface
        document.body.innerHTML = `
            <div class="task-app">
                <header class="app-header">
                    <h1>Interactive Task Manager</h1>
                    <div class="quick-stats">
                        <span id="total-tasks">0 tasks</span>
                        <span id="completed-tasks">0 completed</span>
                    </div>
                </header>
                
                <div class="add-task-section">
                    <form id="task-form" class="task-form">
                        <input type="text" id="task-title" placeholder="What needs to be done?" autocomplete="off">
                        <input type="text" id="task-description" placeholder="Add description (optional)" autocomplete="off">
                        <button type="submit" class="add-btn">Add Task</button>
                    </form>
                </div>
                
                <div class="filter-section">
                    <button class="filter-btn active" data-filter="all">All</button>
                    <button class="filter-btn" data-filter="pending">Pending</button>
                    <button class="filter-btn" data-filter="completed">Completed</button>
                </div>
                
                <div id="tasks-container" class="tasks-container">
                    <div class="empty-state">
                        <p>No tasks yet. Add one above!</p>
                    </div>
                </div>
                
                <div class="bulk-actions">
                    <button id="select-all-btn">Select All</button>
                    <button id="complete-selected-btn">Complete Selected</button>
                    <button id="delete-selected-btn">Delete Selected</button>
                </div>
            </div>
        `;
        
        // Add CSS styles for interactivity
        this.addStyles();
    }
    
    setupEventListeners() {
        // Form submission - single task addition
        document.getElementById('task-form').addEventListener('submit', (e) => {
            e.preventDefault();
            this.handleTaskSubmission();
        });
        
        // Real-time input validation
        document.getElementById('task-title').addEventListener('input', (e) => {
            this.validateInput(e.target);
        });
        
        // Filter buttons
        document.querySelectorAll('.filter-btn').forEach(btn => {
            btn.addEventListener('click', (e) => {
                this.handleFilterChange(e.target.dataset.filter);
            });
        });
        
        // Bulk actions
        document.getElementById('select-all-btn').addEventListener('click', () => {
            this.selectAllTasks();
        });
        
        document.getElementById('complete-selected-btn').addEventListener('click', () => {
            this.completeSelectedTasks();
        });
        
        document.getElementById('delete-selected-btn').addEventListener('click', () => {
            this.deleteSelectedTasks();
        });
        
        // Event delegation for dynamic task elements
        document.getElementById('tasks-container').addEventListener('click', (e) => {
            this.handleTaskInteraction(e);
        });
        
        // Double-click to edit (alternative to button)
        document.getElementById('tasks-container').addEventListener('dblclick', (e) => {
            if (e.target.classList.contains('task-title')) {
                this.enableInlineEditing(e.target);
            }
        });
        
        // Drag and drop for reordering
        document.getElementById('tasks-container').addEventListener('dragstart', (e) => {
            this.handleDragStart(e);
        });
        
        document.getElementById('tasks-container').addEventListener('dragover', (e) => {
            this.handleDragOver(e);
        });
        
        document.getElementById('tasks-container').addEventListener('drop', (e) => {
            this.handleDrop(e);
        });
    }
    
    setupKeyboardShortcuts() {
        // Global keyboard shortcuts
        document.addEventListener('keydown', (e) => {
            // Ctrl/Cmd + Enter: Quick add task
            if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
                document.getElementById('task-title').focus();
            }
            
            // Escape: Cancel current operation
            if (e.key === 'Escape') {
                this.cancelCurrentOperation();
            }
            
            // Delete key: Delete selected tasks
            if (e.key === 'Delete' && !this.isEditing) {
                this.deleteSelectedTasks();
            }
            
            // Ctrl/Cmd + A: Select all tasks
            if ((e.ctrlKey || e.metaKey) && e.key === 'a' && !this.isEditing) {
                e.preventDefault();
                this.selectAllTasks();
            }
        });
    }
    
    handleTaskSubmission() {
        const titleInput = document.getElementById('task-title');
        const descriptionInput = document.getElementById('task-description');
        
        const title = titleInput.value.trim();
        const description = descriptionInput.value.trim();
        
        if (title) {
            this.addTask(title, description);
            titleInput.value = '';
            descriptionInput.value = '';
            titleInput.focus();
        }
    }
    
    addTask(title, description = '') {
        const task = {
            id: this.currentId++,
            title: title,
            description: description,
            completed: false,
            selected: false,
            createdAt: new Date(),
            order: this.tasks.length
        };
        
        this.tasks.push(task);
        this.renderTask(task);
        this.updateStats();
        this.updateEmptyState();
        
        // Show success feedback
        this.showNotification(`Task "${title}" added successfully!`, 'success');
        
        console.log(`Task added: ${title}`);
    }
    
    renderTask(task) {
        const tasksContainer = document.getElementById('tasks-container');
        
        const taskElement = document.createElement('div');
        taskElement.className = `task-item ${task.completed ? 'completed' : ''}`;
        taskElement.dataset.taskId = task.id;
        taskElement.draggable = true;
        
        taskElement.innerHTML = `
            <div class="task-content">
                <input type="checkbox" class="task-checkbox" ${task.selected ? 'checked' : ''}>
                <div class="task-info">
                    <h3 class="task-title" contenteditable="false">${task.title}</h3>
                    ${task.description ? `<p class="task-description">${task.description}</p>` : ''}
                </div>
                <div class="task-actions">
                    <button class="complete-btn" data-action="toggle-complete" title="Toggle completion">
                        ${task.completed ? '✓' : '○'}
                    </button>
                    <button class="edit-btn" data-action="edit" title="Edit task">✎</button>
                    <button class="delete-btn" data-action="delete" title="Delete task">🗑</button>
                </div>
            </div>
        `;
        
        // Add with animation
        taskElement.style.opacity = '0';
        taskElement.style.transform = 'translateY(-20px)';
        tasksContainer.appendChild(taskElement);
        
        // Trigger animation
        requestAnimationFrame(() => {
            taskElement.style.transition = 'all 0.3s ease';
            taskElement.style.opacity = '1';
            taskElement.style.transform = 'translateY(0)';
        });
    }
    
    handleTaskInteraction(event) {
        const taskElement = event.target.closest('.task-item');
        if (!taskElement) return;
        
        const taskId = parseInt(taskElement.dataset.taskId);
        const action = event.target.dataset.action;
        
        switch (action) {
            case 'toggle-complete':
                this.toggleTaskCompletion(taskId);
                break;
            case 'edit':
                this.enableInlineEditing(taskElement.querySelector('.task-title'));
                break;
            case 'delete':
                this.deleteTask(taskId);
                break;
        }
        
        // Handle checkbox selection
        if (event.target.type === 'checkbox') {
            this.toggleTaskSelection(taskId);
        }
    }
    
    toggleTaskCompletion(taskId) {
        const task = this.tasks.find(t => t.id === taskId);
        if (!task) return;
        
        task.completed = !task.completed;
        
        const taskElement = document.querySelector(`[data-task-id="${taskId}"]`);
        taskElement.classList.toggle('completed', task.completed);
        
        const completeBtn = taskElement.querySelector('.complete-btn');
        completeBtn.textContent = task.completed ? '✓' : '○';
        
        // Animation feedback
        taskElement.style.transform = 'scale(1.05)';
        setTimeout(() => {
            taskElement.style.transform = 'scale(1)';
        }, 150);
        
        this.updateStats();
        this.showNotification(
            `Task "${task.title}" ${task.completed ? 'completed' : 'reopened'}!`,
            task.completed ? 'success' : 'info'
        );
    }
    
    enableInlineEditing(titleElement) {
        if (this.isEditing) return;
        
        this.isEditing = true;
        const originalTitle = titleElement.textContent;
        
        titleElement.contentEditable = true;
        titleElement.classList.add('editing');
        titleElement.focus();
        
        // Select all text
        const range = document.createRange();
        range.selectNodeContents(titleElement);
        const selection = window.getSelection();
        selection.removeAllRanges();
        selection.addRange(range);
        
        const saveEdit = () => {
            const newTitle = titleElement.textContent.trim();
            if (newTitle && newTitle !== originalTitle) {
                const taskId = parseInt(titleElement.closest('.task-item').dataset.taskId);
                const task = this.tasks.find(t => t.id === taskId);
                if (task) {
                    task.title = newTitle;
                    this.showNotification('Task updated successfully!', 'success');
                }
            } else if (!newTitle) {
                titleElement.textContent = originalTitle;
            }
            
            titleElement.contentEditable = false;
            titleElement.classList.remove('editing');
            this.isEditing = false;
        };
        
        const cancelEdit = () => {
            titleElement.textContent = originalTitle;
            titleElement.contentEditable = false;
            titleElement.classList.remove('editing');
            this.isEditing = false;
        };
        
        // Save on Enter, cancel on Escape
        titleElement.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') {
                e.preventDefault();
                saveEdit();
            } else if (e.key === 'Escape') {
                e.preventDefault();
                cancelEdit();
            }
        });
        
        // Save on blur
        titleElement.addEventListener('blur', saveEdit, { once: true });
    }
    
    handleFilterChange(filter) {
        // Update active filter button
        document.querySelectorAll('.filter-btn').forEach(btn => {
            btn.classList.remove('active');
        });
        document.querySelector(`[data-filter="${filter}"]`).classList.add('active');
        
        // Filter tasks
        document.querySelectorAll('.task-item').forEach(taskElement => {
            const taskId = parseInt(taskElement.dataset.taskId);
            const task = this.tasks.find(t => t.id === taskId);
            
            let shouldShow = true;
            
            switch (filter) {
                case 'pending':
                    shouldShow = !task.completed;
                    break;
                case 'completed':
                    shouldShow = task.completed;
                    break;
                case 'all':
                default:
                    shouldShow = true;
                    break;
            }
            
            taskElement.style.display = shouldShow ? 'block' : 'none';
        });
    }
    
    updateStats() {
        const total = this.tasks.length;
        const completed = this.tasks.filter(t => t.completed).length;
        
        document.getElementById('total-tasks').textContent = `${total} task${total !== 1 ? 's' : ''}`;
        document.getElementById('completed-tasks').textContent = `${completed} completed`;
    }
    
    updateEmptyState() {
        const emptyState = document.querySelector('.empty-state');
        const hasTasks = this.tasks.length > 0;
        emptyState.style.display = hasTasks ? 'none' : 'block';
    }
    
    showNotification(message, type = 'info') {
        // Create and show notification
        const notification = document.createElement('div');
        notification.className = `notification ${type}`;
        notification.textContent = message;
        
        document.body.appendChild(notification);
        
        // Auto-remove after 3 seconds
        setTimeout(() => {
            notification.remove();
        }, 3000);
    }
    
    addStyles() {
        const style = document.createElement('style');
        style.textContent = `
            .task-app { max-width: 800px; margin: 0 auto; padding: 20px; font-family: Arial, sans-serif; }
            .app-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px; }
            .quick-stats span { margin-left: 20px; color: #666; }
            .task-form { display: flex; gap: 10px; margin-bottom: 20px; }
            .task-form input { flex: 1; padding: 10px; border: 1px solid #ddd; border-radius: 4px; }
            .add-btn { padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }
            .filter-section { display: flex; gap: 10px; margin-bottom: 20px; }
            .filter-btn { padding: 8px 16px; border: 1px solid #ddd; background: white; cursor: pointer; border-radius: 4px; }
            .filter-btn.active { background: #007bff; color: white; }
            .task-item { background: white; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 10px; padding: 15px; transition: all 0.3s ease; }
            .task-item.completed { opacity: 0.7; }
            .task-content { display: flex; align-items: center; gap: 15px; }
            .task-info { flex: 1; }
            .task-title { margin: 0; cursor: text; }
            .task-title.editing { background: #f9f9f9; padding: 5px; border-radius: 3px; }
            .task-actions { display: flex; gap: 5px; }
            .task-actions button { background: none; border: none; cursor: pointer; padding: 5px; border-radius: 3px; }
            .task-actions button:hover { background: #f0f0f0; }
            .empty-state { text-align: center; color: #666; padding: 40px; }
            .bulk-actions { margin-top: 20px; display: flex; gap: 10px; }
            .bulk-actions button { padding: 8px 16px; border: 1px solid #ddd; background: white; cursor: pointer; border-radius: 4px; }
            .notification { position: fixed; top: 20px; right: 20px; padding: 15px; border-radius: 4px; color: white; z-index: 1000; }
            .notification.success { background: #28a745; }
            .notification.info { background: #17a2b8; }
            .notification.error { background: #dc3545; }
        `;
        document.head.appendChild(style);
    }
}

// Initialize interactive task manager
const interactiveTaskManager = new InteractiveTaskManager();

// Add some sample tasks
interactiveTaskManager.addTask("Learn DOM Events", "Master event handling in JavaScript");
interactiveTaskManager.addTask("Build Interactive UI", "Create responsive user interfaces");
interactiveTaskManager.addTask("Handle User Input", "Process forms and user interactions");

// JavaScript event-driven characteristics:
// 1. Multiple concurrent user interactions
// 2. Real-time visual feedback
// 3. Asynchronous event processing
// 4. Rich user interface elements
console.log("JavaScript: Event-driven interface with real-time interactions and visual feedback");
```
</PythonEditor>

## Summary and Key Takeaways

DOM manipulation and event handling are fundamental skills for creating interactive web applications:

### 🔄 **Core Concepts**
- **DOM as Data Structure**: The DOM is a live, visual data structure that you manipulate like Python lists and dictionaries
- **Event-Driven Programming**: User interactions trigger events that execute your code asynchronously
- **Visual Feedback**: Every data change can immediately reflect in the user interface

### 🛠 **Essential Techniques**
- **Element Creation and Manipulation**: Programmatically create and modify HTML elements
- **Event Listeners**: Respond to user actions like clicks, keyboard input, and form submissions
- **Event Delegation**: Efficiently handle events on dynamic content using event bubbling

### 📱 **User Experience Enhancement**
- **Real-time Updates**: Provide immediate feedback for user actions
- **Interactive Elements**: Create engaging interfaces with animations and transitions
- **Accessibility**: Ensure your interfaces work for all users with proper keyboard support

In the next module, we'll explore web frameworks and how they simplify the process of building complex interactive applications while maintaining the core principles you've learned here.
